#include "mcu_init.h"
#include "tos_k.h"
#include "mqttclient.h"
#include "cJSON.h"
#include "sal_module_wrapper.h"
#include "mqtt_config.h"
#include "E53_SC1.h"
#include "ec600s.h"

k_event_t report_result_event;
k_event_flag_t report_success = 1 << 0;
k_event_flag_t report_fail = 1 << 1;

static char is_light_switch_changed = 1;
static char is_client_token_received = 0;

int light_switch_cache = 0;
char client_token_cache[128] = { 0 };

/***************************************************************
* 函数名称: HAL_GPIO_EXTI_Callback
* 说    明: 按键处理回调
***************************************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch(GPIO_Pin)
    {
        case KEY1_Pin:
            if (LIGHT_IS_OPEN) {
                printf("iot-explorer close the light\r\n");
                E53_SC1_Light_Set(OFF);
                is_light_switch_changed = 1;
                light_switch_cache = 0;
            } else {
                E53_SC1_Light_Set(ON);
                is_light_switch_changed = 1;
                light_switch_cache = 1;
                printf("iot-explorer open the light\r\n");
            }            
            break;
        default:
            break;
    }
}

/***************************************************************
* 函数名称: iot_explorer_handle_light_switch
* 说    明: 根据power switch控制开关
***************************************************************/
static void iot_explorer_handle_light_switch(int light_switch)
{
    light_switch_cache = light_switch;

    if (0 == light_switch) {
        if (LIGHT_IS_OPEN) {
            printf("iot-explorer close the light\r\n");
            E53_SC1_Light_Set(OFF);
            is_light_switch_changed = 1;
        } else {
            printf("the light already closed\r\n");
        }
    } else {
        if (LIGHT_IS_OPEN) {
            printf("the light already opened\r\n");
        } else {
            printf("iot-explorer open the light\r\n");
            E53_SC1_Light_Set(ON);
            is_light_switch_changed = 1;
        }
    }
}


/***************************************************************
* 函数名称: tos_topic_handler
* 说    明: IoT Explorer下行数据处理
***************************************************************/
static void tos_topic_handler(void* client, message_data_t* msg)
{
    cJSON *root;
    cJSON *params;
    cJSON *token;
    cJSON *method;
    cJSON *light_switch;
    cJSON* cjson_status = NULL;
    char* status = NULL;
    k_event_flag_t event_flag = report_fail;

    /* 打印日志 */
    MQTT_LOG_I("-----------------------------------------------------------------------------------");
    MQTT_LOG_I("%s:%d %s()...\ntopic: %s, qos: %d. \nmessage:\n\t%s\n", __FILE__, __LINE__, __FUNCTION__,
            msg->topic_name, msg->message->qos, (char*)msg->message->payload);
    MQTT_LOG_I("-----------------------------------------------------------------------------------\n");

    // 1. 解析从云端收到的控制信息，示例控制信息为
    //"{"method":"control","clientToken":"clientToken-Xx-N_enad","params":{"power_switch":0}}"
    root = cJSON_Parse((char*)msg->message->payload);
    if (root == NULL) {
        printf("report reply message parser fail\r\n");
        cJSON_Delete(root);
        return;
    }

    // 2. 解析出method
    method = cJSON_GetObjectItem(root, "method");
    if (!method) {
        printf("Invalid json method\r\n");
        cJSON_Delete(root);
        return;
    }

    // 3. 仅处理云端下发的 control 数据
    if (0 == strncmp(method->valuestring, "control", sizeof("control") - 1)) {

        // 4. 解析出params
        params = cJSON_GetObjectItem(root, "params");
        if (params) {
        // 5. 解析出 开关指令
            light_switch = cJSON_GetObjectItem(params, "light_switch");
            // 根据 light_switch 控制实际硬件开关
            if (light_switch) {
                iot_explorer_handle_light_switch(light_switch->valueint);
            }
        }
        // 6. 设置clientToken回复
        token = cJSON_GetObjectItem(root, "clientToken");
        if (token) {
            strcpy(client_token_cache, token->valuestring);
            is_client_token_received = 1;
        }
        cJSON_Delete(root);
        return;
    }

    // 6. 解析出数据上报后平台回复的上报状态
    cjson_status = cJSON_GetObjectItem(root, "status");
    if (cjson_status) {
        // 7. 获取上报状态，判断上报成功或失败
        status = cJSON_GetStringValue(cjson_status);
        if (status == NULL) {
            printf("report reply status parser fail\r\n");
            event_flag = report_fail;
        } else {
            if (strstr(status, "success")) {
                event_flag = report_success;
            } else {
                event_flag = report_fail;
            }
        }
        cJSON_Delete(root);
        root = NULL;
        status = NULL;
        // 8. 触发事件
        tos_event_post(&report_result_event, event_flag);
        return;
    }
}

#define REPORT_LIGHT_DATA_TEMPLATE  "{\"method\":\"report\",\"clientToken\":\"00000001\",\"params\":{\"light_switch\":%d}}"
#define REPORT_SENSOR_DATA_TEMPLATE "{\"method\":\"report\",\"clientToken\":\"00000001\",\"params\":{\"lum\":%d}}"
#define CONTROL_REPLY_DATA_TEMPLATE "{\"method\":\"control_reply\",\"clientToken\":\"%s\",\"code\":0,\"status\":\"ok\"}"

char report_buf[200];

/***************************************************************
* 函数名称: mqttclient_task
* 说    明: 主任务，连接平台以及发送上行数据
***************************************************************/
void mqttclient_task(void)
{
    int error;

    mqtt_client_t *client = NULL;

    mqtt_message_t msg;

    k_event_flag_t match_flag;

    E53_SC1_Data  data;

    char  host_ip[20];

    memset(&msg, 0, sizeof(msg));

    ec600s_sal_init(HAL_UART_PORT_0);

    mqtt_log_init();

    client = mqtt_lease();

    tos_event_create(&report_result_event, (k_event_flag_t)0u);

    /* Domain Format: <your product ID>.iotcloud.tencentdevices.com */
    tos_sal_module_parse_domain(MQTT_SERVER_DOMAIN, host_ip, sizeof(host_ip));
    /*
        These infomation is generated by mqtt_config_gen.py tool in "TencentOS-tiny\tools" directory.
    */
    mqtt_set_port(client, MQTT_SERVER_PORT);
    mqtt_set_host(client, host_ip);
    mqtt_set_client_id(client, MQTT_CLIENT_ID);
    mqtt_set_user_name(client, MQTT_USR_NAME);
    mqtt_set_password(client, MQTT_PASSWORD);
    mqtt_set_clean_session(client, 1);

    error = mqtt_connect(client);

    MQTT_LOG_D("mqtt connect error is %#0x", error);

    error = mqtt_subscribe(client, MQTT_SUBSCRIBE_TOPIC_DOWN, QOS0, tos_topic_handler);

    MQTT_LOG_D("mqtt subscribe error is %#0x", error);

    while (1) {

        /* 上报传感器数据 */
        E53_SC1_Read_Data(&data);
        LCD_ShowCharStr(10, 110, "Luminance:", WHITE, BLUE, 24);
        LCD_ShowNum(140, 110, (int)data.Lux, 5, WHITE, BLUE, 24);
        memset(&msg, 0, sizeof(msg));
        memset(report_buf, 0, sizeof(report_buf));
        snprintf(report_buf, sizeof(report_buf), REPORT_SENSOR_DATA_TEMPLATE, (int)data.Lux);
        msg.qos = QOS0;
        msg.payload = (void *)report_buf;
        error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);
        MQTT_LOG_D("mqtt publish error is %#0x", error);
        tos_event_pend(&report_result_event,
                       report_success | report_fail,
                       &match_flag,
                       TOS_TIME_FOREVER,
                       TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);

        if (match_flag == report_success) {
            printf("report to Tencent IoT Explorer success\r\n");

        } else if (match_flag == report_fail) {
            printf("report to Tencent IoT Explorer fail\r\n");
        }
        /* END*/

        /* 如果灯状态发生改变，则上报灯的状态 */
        if (is_light_switch_changed) {
            is_light_switch_changed = 0;
            LCD_ShowCharStr(10, 80, "Light:", WHITE, BLUE, 24);
            LCD_ShowCharStr(140, 80, light_switch_cache?"ON ":"OFF", WHITE, BLUE, 24);
            
            memset(&msg, 0, sizeof(msg));
            memset(report_buf, 0, sizeof(report_buf));
            snprintf(report_buf, sizeof(report_buf), REPORT_LIGHT_DATA_TEMPLATE, light_switch_cache);
            msg.qos = QOS0;
            msg.payload = (void *)report_buf;
            error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);

            MQTT_LOG_D("mqtt publish error is %#0x", error);
            tos_event_pend(&report_result_event,
                       report_success | report_fail,
                       &match_flag,
                       TOS_TIME_FOREVER,
                       TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);

            if (match_flag == report_success) {
                printf("report to Tencent IoT Explorer success\r\n");

            } else if (match_flag == report_fail) {
                printf("report to Tencent IoT Explorer fail\r\n");
            }
        }
        /* END*/
        
        /* 接受到下行control消息，回复最近一条 */
        if (is_client_token_received) {
        	is_client_token_received = 0;
            memset(&msg, 0, sizeof(msg));
            memset(report_buf, 0, sizeof(report_buf));
            snprintf(report_buf, sizeof(report_buf), CONTROL_REPLY_DATA_TEMPLATE, client_token_cache);
            msg.qos = QOS0;
            msg.payload = (void *) report_buf;
            error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);

            MQTT_LOG_D("mqtt publish error is %#0x", error);
        }
        /* END*/
        
        tos_task_delay(5000);
    }
}

/***************************************************************
* 函数名称: application_entry
* 说    明: 应用入口
***************************************************************/
void application_entry(void *arg)
{
    E53_SC1_Init();
    mqttclient_task();
    while (1) {
        printf("This is a mqtt demo!\r\n");
        tos_task_delay(1000);
    }
}
